package com.ssamkj.ann;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;


public class AnnClass {
	float[] Hidden_output = new float[1];

	float[] Last_output = new float[1];

	float[][] Wji = new float[1][1];
	float[][] Wkj = new float[1][1];

	float[] O_pi = new float[1];
	float[] NET_pj = new float[1];
	float[] O_pj = new float[1];
	float[] NET_pk = new float[1];
	float[] O_pk = new float[1];

	int inputNodeNum = 0;
	int outputNodeNum = 0;
	int hiddenNodeNum = 0;

	float[] Dpk = new float[1];
	float[] Dpj = new float[1];

	float[][] D_Wji = new float[1][1];
	float[][] D_Wkj = new float[1][1];

	float Gama = 0.3F;
	float S_rate = 0.3F;

	float[][] L_Wkj = new float[1][1];
	float[][] L_Wji = new float[1][1];

	ValueSave vm = new ValueSave();

	public void initANN(int inputNode_Num, int outputNode_Num,
			int hiddenNode_Num, float LearningRate, float Moment) {
		this.S_rate = LearningRate;
		this.Gama = Moment;
		this.inputNodeNum = inputNode_Num;
		this.outputNodeNum = outputNode_Num;
		this.hiddenNodeNum = hiddenNode_Num;

		this.O_pi = new float[inputNode_Num];
		this.NET_pj = new float[hiddenNode_Num];
		this.O_pj = new float[hiddenNode_Num];
		this.NET_pk = new float[outputNode_Num];
		this.O_pk = new float[outputNode_Num];

		this.Wji = new float[inputNode_Num][hiddenNode_Num];

		this.Wkj = new float[hiddenNode_Num][outputNode_Num];
		this.Hidden_output = new float[hiddenNode_Num];

		this.Last_output = new float[outputNode_Num];

		for (int i = 0; i < inputNode_Num; i++) {
			for (int j = 0; j < hiddenNode_Num; j++)
				this.Wji[i][j] = ((float) Math.cos(i + j) / 2.0F);

		}

		for (int i = 0; i < hiddenNode_Num; i++) {
			for (int j = 0; j < outputNode_Num; j++)
				this.Wkj[i][j] = ((float) Math.sin(i * 3 + j * 2) / 2.0F);

		}

		this.Dpk = new float[outputNode_Num];
		this.Dpj = new float[hiddenNode_Num];
		this.D_Wji = new float[inputNode_Num][hiddenNode_Num];
		this.D_Wkj = new float[hiddenNode_Num][outputNode_Num];

		this.L_Wkj = new float[hiddenNode_Num][outputNode_Num];
		this.L_Wji = new float[inputNode_Num][hiddenNode_Num];
	}

	public void Setinput(float[] inputArray) {
		this.O_pi = inputArray;
	}

	public float[] Calc_Pattern() {
		for (int i = 0; i < this.hiddenNodeNum; i++) {
			float Sum = 0.0F;
			for (int j = 0; j < this.inputNodeNum; j++) {
				Sum += this.Wji[j][i] * this.O_pi[j];
			}

			this.NET_pj[i] = Sum;
			this.O_pj[i] = sigmoid(this.NET_pj[i]);
		}

		for (int k = 0; k < this.outputNodeNum; k++) {
			float Sum = 0.0F;
			for (int i = 0; i < this.hiddenNodeNum; i++) {
				Sum += this.Wkj[i][k] * this.O_pj[i];
			}

			this.NET_pk[k] = Sum;
			this.O_pk[k] = sigmoid(this.NET_pk[k]);
		}

		return this.O_pk;
	}

	public float Learning(float[] Target) {
		for (int k = 0; k < this.outputNodeNum; k++) {
			this.Dpk[k] = ((Target[k] - this.O_pk[k]) * sigmoid(this.NET_pk[k]));
		}

		for (int i = 0; i < this.hiddenNodeNum; i++) {
			for (int j = 0; j < this.outputNodeNum; j++) {
				this.D_Wkj[i][j] = (this.S_rate * this.Dpk[j] * this.O_pj[i]);

				this.Wkj[i][j] += this.D_Wkj[i][j];
			}

		}

		for (int i = 0; i < this.hiddenNodeNum; i++) {
			float Sum = 0.0F;
			for (int k = 0; k < this.outputNodeNum; k++) {
				Sum += this.Dpk[k] * this.Wkj[i][k];
			}
			this.Dpj[i] = (this.O_pj[i] * (1.0F - this.O_pj[i]) * Sum);
		}

		for (int i = 0; i < this.inputNodeNum; i++) {
			for (int j = 0; j < this.hiddenNodeNum; j++) {
				this.D_Wji[i][j] = (this.S_rate * this.Dpj[j] * this.O_pi[i]);

				this.Wji[i][j] += this.D_Wji[i][j];
			}

		}

		float Err = 0.0F;

		for (int i = 0; i < this.O_pk.length; i++) {
			Err = (float) (Err + Math.pow(Target[i] - this.O_pk[i], 2.0D) / 2.0D);
		}

		return Err;
	}

	private ValueSave loadOption(File optionFile) {
		ValueSave optionData;
		try {
			ObjectInputStream is = new ObjectInputStream(new FileInputStream(
					optionFile));
			optionData = (ValueSave) is.readObject();
			is.close();
			return optionData;
		} catch (Exception ex) {
			ex.printStackTrace();

			optionData = new ValueSave();
			saveOption(optionFile, optionData);
		}
		return optionData;
	}

	private void saveOption(File optionFile, ValueSave optionData) {
		try {
			ObjectOutputStream os = new ObjectOutputStream(
					new FileOutputStream(optionFile));
			os.writeObject(optionData);
			os.flush();
			os.close();
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
	}

	public void Out_ANNset(String fDir) {
		this.vm.ow = this.Wji;

		this.vm.iw = this.Wkj;

		this.vm.hav = this.O_pi;
		this.vm.oav = this.O_pk;

		this.vm.hiddennum = this.hiddenNodeNum;

		String str_Path_Full = fDir;
		File file = new File(str_Path_Full);
		if (!file.exists())
			try {
				file.createNewFile();
			} catch (IOException localIOException) {
			}
		saveOption(file, this.vm);
	}

	public void Get_ANNsave(String fDir) {
		String str_Path_Full = fDir;
		File file = new File(str_Path_Full);

		this.vm = loadOption(file);
		initANN(this.vm.hav.length, this.vm.oav.length, this.vm.hiddennum,
				0.05F, 0.04F);
		this.Wji = this.vm.ow;

		this.Wkj = this.vm.iw;
	}

	public float sigmoid(float x) {
		return 1.0F / (1.0F + (float) Math.exp(-1.0F * x));
	}
}